package com.panopset.flywheel;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;

import com.panopset.compat.Logz;
import com.panopset.compat.RezIO;
import com.panopset.compat.Strings;
import com.panopset.io.Filez;

/**
 * Publish a suite of JNLP files, based on a package that only contains classes
 * that extend SwingFrame or a superclass of SwingFrame.
 * 
 * @author Karl Dinwiddie
 * 
 */
public class PublishJNLP {

	/**
	 * @param args
	 *            0: Project base directory. 1: Package name. 2: Publish to
	 *            directory. 3: Publication home page.
	 */
	public static void main(final String[] args) {
		if (args == null || args.length != 4) {
			printUsage();
			return;
		}
		new PublishJNLP(args[0], args[1], args[2], args[3]).publish();
	}

	private String mainJar;

	private String getMainJar() {
		if (mainJar == null) {
			getDepJars();
			if (mainJar == null) {
				mainJar = "No main jar found.";
			}
		}
		return mainJar;
	}

	private List<String> depJars;

	private List<String> getDepJars() {
		if (depJars == null) {
			depJars = new ArrayList<String>();
			for (String d : getJarNames()) {
				if (d.indexOf(bd.getName()) == 0) {
					mainJar = d;
				} else {
					depJars.add(d);
				}
			}
		}
		return depJars;
	}

	private File targJnlpDir;

	private File getTargJnlpDir() {
		if (targJnlpDir == null) {
			targJnlpDir = new File(fz.combinePaths(new File(todir), "jnlplib"));
		}
		return targJnlpDir;
	}

	private List<String> jarNames;

	private List<String> getJarNames() {
		if (jarNames == null) {
			jarNames = new ArrayList<String>();
			for (File f : getTargJnlpDir().listFiles()) {
				jarNames.add(f.getName());
			}
		}
		return jarNames;
	}

	private String getDependencyJarReferences() {
		StringWriter sw = new StringWriter();
		for (String s : getDepJars()) {
			sw.append("    <jar href=\"jnlplib/");
			sw.append(s);
			sw.append("\"/>");
			sw.append(sz.getEol());
		}
		return sw.toString();
	}

	private void publishClass(final File f) {
		String jnlpName = FilenameUtils.removeExtension(f.getName())
				.toLowerCase();
		File outFile = new File(fz.combinePaths(new File(todir), jnlpName
				+ ".jnlp"));
		outFile.delete();
		try {
			FileUtils.writeStringToFile(outFile, new Flywheel.Builder().input(

			RezIO.loadLinesFromResource("/com/panopset/jnlp.txt"))

			.map("mainjar", getMainJar())

			.map("homepage", hp)

			.map("dependencies", getDependencyJarReferences())

			.construct().exec());
			Logz.log("Created: " + fz.getCanonicalPath(outFile));
		} catch (IOException e) {
			Logz.log(e);
		}
	}

	private void publish() {
		Logz.log("Base directory: " + bd);
		Logz.log("Package: " + pkg);
		Logz.log("To directory: " + todir);
		Logz.log("Home page: " + hp);
		File pkgDir = new File(fz.combinePaths(bd,

		"src/main/java/" + pkg.replace(".", "/")));
		Logz.log("pkgDir : " + fz.getCanonicalPath(pkgDir));
		if (!pkgDir.exists()) {
			Logz.log("Could not find package " + pkg);
			return;
		}
		for (File f : pkgDir.listFiles()) {
			if (f.getName().indexOf("package-info.java") == -1) {
				publishClass(f);
			}
		}
	}

	private final File bd;
	private final String pkg;
	private final String todir;
	private final String hp;

	/**
	 * 
	 * @param baseDirectory
	 *            JNLP base directory.
	 * @param packageName
	 *            Package that all the JNLP app entry classes are found. This
	 *            package should have no other classes, because a JNLP file will
	 *            be created for each one.
	 * @param toDirectory
	 *            Source for site publication, where the jnlp files will be
	 *            staged, and under which the mvnrepo directory will be created.
	 * @param homepage
	 *            This is the home page, where the jnlp files will be published.
	 *            For testing, pass 127.0.0.1.
	 */
	private PublishJNLP(final String baseDirectory, final String packageName,
			final String toDirectory, final String homepage) {
		bd = new File(baseDirectory);
		pkg = packageName;
		todir = toDirectory;
		hp = homepage;
	}

	private static void printUsage() {
		System.out.println(getUsageMessage());
	}

	private static String getUsageMessage() {
		String eol = new Strings().getEol();
		StringWriter sw = new StringWriter();
		sw.append("Usage:");
		sw.append(eol);
		sw.append("java PublishJNLPsuite basedir package todir codebase");
		sw.append(eol);
		sw.append(" where basedir is the JNLP suite project directory,");
		sw.append(eol);
		sw.append("       package is the package of the JNLP suite classes,");
		sw.append(eol);
		sw.append("       todir is where the JNLP files are to be published,");
		sw.append(eol);
		sw.append("       codebase is the JNLP codebase,");
		sw.append(eol);
		return sw.toString();
	}

	private final Filez fz = new Filez();
	private final Strings sz = new Strings();
}
